下午好困啊 …写篇 blog 比较提神。
定义
动态给一个对象增加一些额外的职责,属于一种对象结构型模式。
结构
UML图
由图中为我们可以看到一共有四个类,两层的继承关系以及一层聚合关系;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Component { constructor() {} operation() {} } class ConcreteComponent extends Component { constructor() {} operation() {} } class Decorator extends Component { constructor() {} operation() {} } class ConcreteDecoratorA extends Decorator { constructor() {} operation() {} addBehavior() {} }
|
时序图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class Component { constructor() {} operation() { console.error('请重写 operation 的方法!'); } } class ConcreteComponent extends Component { constructor() { super(); } operation() { console.log('ConcreteComponent\'s normal operation!'); } } class Decorator extends Component { constructor(component) { super(); this.component = component; } operation() { this.component.operation(); if (typeof this.addBehavior === 'function') { this.addBehavior(); } else { console.error('请定义 addBehavior 方法'); } } } class ConcreteDecoratorA extends Decorator { constructor(component) { super(component); } addBehavior() { console.log('addBehavior AAA'); } } const component = new ConcreteComponent(); const decoratorA = new ConcreteDecoratorA(component); decoratorA.operation();
|
以上来自图解设计模式的对于装饰模式的实现。
但是这样的实现非常的绕,在《 JavaScript设计模式与开发实践 》中有提到用 AOP 的方式实现装饰函数。
AOP
面向切面编程,这是一种函数式编程的衍生物,以函数为基本单元,在一个函数的执行前或者执行后插入一个新的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const before = function(fn, beforeFn) { return function(...types) { beforeFn.apply(this, types); return fn.apply(this, types); } } const after = function(fn, afterFn) { return function(...types) { const ret = fn.apply(this, types); afterFn.apply(this, types); return ret; } } function testFn(name) { console.log('AOP' + ' ' + name); } const testFn = before( testFn, function(name) { console.log(name) } ); testFn('Hello World');
|
以上就是对于装饰器的实现,其实装饰器在许多语言中都已经是内置实现了,比如 python:
1 2 3 4 5 6 7 8 9 10
| def log(func): def wrapper(*args, **kw): print('wrapper') return func(*args, **kw) return wrapper @log def now(): print('2017-06-12')
|
其实这里的实现也是返回函数的高阶函数的实现。
在 ES6 的 Class 也有了对装饰器的内置实现(但是目前不支持对于普通函数),并且需要 babel 的实现。
可以参考阮老师的修饰器的文章
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class TestObj { constructor() {} @log test() { console.log('Hello ES6 Class Wrapper!'); } } function log(target, name, descriptor) { const oldValue = descriptor.value; descriptor.value = function(...types) { console.log(`Calling "${name}" with`, types); return oldValue.apply(this, arguments); } return descriptor; } const testObj = new TestObj(); testObj.test();
|
Java 实现
1 2 3
| public interface Shape { void draw(); }
|
1 2 3 4 5
| public class Circle implements Shape { public void draw() { System.out.println("Shape: Circle"); } }
|
1 2 3 4 5 6 7 8 9
| public abstract class ShapeDecorator implements Shape { Shape decoratedShape; public ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; } public abstract void draw(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class RedBoardDecorator extends ShapeDecorator { public RedBoardDecorator(Shape decroatedShape) { super(decroatedShape); } @Override public void draw() { this.decoratedShape.draw(); this.setRedBorad(); } public void setRedBorad() { System.out.println("Board: Red!"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| import com.decorator.Circle; import com.decorator.RedBoardDecorator; public class Main { public static void main(String[] args) { Circle circle = new Circle(); RedBoardDecorator redBoradCircle = new RedBoardDecorator(circle); redBoradCircle.draw(); } }
|
总结
装饰器是一种十分常见的设计模式,在一个项目的基础架构上有许多地方会用到这种设计模式。
它提供了一种动态的方式扩展一个对象的功能。
图解设计模式
廖雪峰的python教程
ES6 修饰器